import 'package:flutter/widgets.dart';
import 'dva-hooks.dart';
import 'dva-model.dart';
import 'dva-reducer.dart';
import 'redux.dart';

typedef Widget WidgetCreatorFunction();
typedef Future FutureCallbackFunction();

class DvaOpts extends DvaHook {
  DvaOpts({ 
    required this.models, 
    this.initialState, 
    ErrorEventFunction? onError,
    ActionEventFunction? onAction, 
    StateChangeEventFunction? onStateChange, 
    UseReducerFunction? useReducer, 
    UseEffectFunction? useEffect,
    Map<String, DvaReducer>? extraReducers,
    List<StoreEnhancer>? extraEnhancers,
  }) : super(
    onAction: onAction,
    onError: onError,
    onStateChange: onStateChange,
    useReducer: useReducer,
    useEffect: useEffect,
    extraReducers: extraReducers,
    extraEnhancers: extraEnhancers,
  );

  List<Model> models;
  Map<String, StoreOfState>? initialState;
}

class Dva {
   Dva(this.opts) {
    opts.models.forEach((model) {
      // 如果DvaOpts中包含了initialState，且initialState中包含model.namespace一样的key，则会优先已opts.initialState[model.namespace] 取值给model的初始
      model.state = 
        opts.initialState != null && opts.initialState!.containsKey(model.namespace) 
          ? opts.initialState![model.namespace]! : model.state;
      models[model.namespace] = model;
    });
    plugin.use(opts);
  }
  DvaOpts opts;
  Map<String, Model> models = <String, Model>{};
  Store? store;
  RootReducer rootReducer = RootReducer();
  Map<String, Reducer<dynamic>> reducers = <String, Reducer<dynamic>>{};
  DvaPlugin plugin = DvaPlugin();

  void use(DvaHook hook) {
    plugin.use(hook);
  }
  
  RootReducer createRootReducer() {
    models.forEach((key, model) {
      reducers[key] = DvaReducer<dynamic>(
        model: model, 
        store: store, 
        onStateChange: plugin.onStateChange,
        useEffect: plugin.useEffect
      );
    });

    /// 合并extraReducers
    for(Reducer reducer in plugin.extraReducers.values) {
      /// 传递/复写store给扩展reducer
      reducer.store = store;
    }
    reducers.addAll(plugin.extraReducers);

    rootReducer.combineReducers(reducers);
    /// useReducer
    rootReducer = plugin.useReducer(rootReducer);
    rootReducer.onError = (dynamic error, Map<String, dynamic> context){
      plugin.onError(error, context);
    };
    rootReducer.onAction = (DvaAction action) {
      plugin.onAction(action);
    };
    rootReducer.useRunReducer = plugin.useRunReducer;
    return rootReducer;
  }

  Future<WidgetCreatorFunction> start(WidgetCreatorFunction widgetCreator, FutureCallbackFunction callback, { bool waitCallabck = false }) async {
    StoreCreator storeCreator = createStore;
    /// storeEnhancer hook
    storeCreator = plugin.storeEnhancer(storeCreator);
    /// 创建store
    store = storeCreator(createRootReducer());
    store!.rootReducer.reducers.forEach((key, reducer)=> (reducer as DvaReducer).store = store!);
    final Provider provider = Provider();
    provider.store = store;
    if(waitCallabck) {
      await callback();
    } else {
      callback();
    }
    await Future<dynamic>.delayed(Duration(milliseconds: 10));
    return () => widgetCreator();
  }
}